/*
 * UI.java
 *
 * Created on 05. Juni 2007, 01:46
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package sbc;

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.xvsm.api.core.*;
import org.xvsm.client.ClientCapi;
import org.xvsm.api.core.notification.*;
import sbc.repos.Board;
import sbc.repos.Feature;
import sbc.repos.Sensor;
import sbc.repos.ModuleFactory;
import sbc.util.*;

import org.apache.log4j.*;

/**
 *
 * @author mustermark
 */
public class UI {
    
    private JTable boardTable, sensorTable;
    private Capi capi;
    private static JFrame f;
    private ContainerRef cref;
    static Logger logger = Logger.getLogger(UI.class);
    
    
    /** Creates a new instance of UI */
    public UI(Capi c, ContainerRef cr) {
        //capi = new ClientCapi(url);
        cref = cr;
        capi = c;
        //final JFrame f = new JFrame("Patinenfabrik");
        f = new JFrame("Patinenfabrik");
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        f.setContentPane(createContent());
        f.setSize((int)(screenSize.width), (int)(screenSize.height));
        f.setVisible(true);
        f.addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent e) {
                System.out.println("Bye.");
                System.exit(0);
            }
        });
        
    }
    
    protected Container createContent() {
        JPanel content = new JPanel(new BorderLayout());
        boardTable = new JTable(new DefaultTableModel());
        JPanel buttonPanel = new JPanel();
        JButton writeBoard = new JButton("neue Platine");
        JButton writeSensor = new JButton("neuer Sensor");
        writeBoard.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showBoardDialog();
            }
        });
        writeSensor.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showSensorDialog();
            }
        });
        buttonPanel.add(writeBoard);
        buttonPanel.add(writeSensor);
        JPanel p = new JPanel(new BorderLayout());
        p.add(buttonPanel, BorderLayout.NORTH);
        
        final JTextField relationField = new JTextField(7);
        relationField.setText("1:2");
        final JTextField timeField = new JTextField(7);
        timeField.setText("60");
        JButton benchmarkButton = new JButton("start benchmark");
        benchmarkButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    int boards = Integer.valueOf(relationField.getText().substring(0,1));
                    int sensors = Integer.valueOf(relationField.getText().substring(2,3));
                    int relation = (sensors/boards > 1) ? sensors/boards : 0;
                    int milliSecs = Integer.valueOf(timeField.getText())*1000;
                    runBenchmark(relation, milliSecs);
                } catch(Exception exx) { 
                    logger.error("Error running benchmark", exx);
                    JOptionPane.showMessageDialog(f, "Exception occured. Check relation and time input!", exx.getMessage(), JOptionPane.ERROR_MESSAGE); 
                }
            }
        });
        JPanel benchPanel = new JPanel(new BorderLayout());
        JPanel p1 = new JPanel();
        //p1.add(benchmarkButton);
        p1.add(new JLabel("Relation(Board:Sensor): "));
        p1.add(relationField);
        JPanel p2 = new JPanel();
        p2.add(new JLabel("time to run: "));
        p2.add(timeField);
        p2.add(new JLabel("secs"));
        JPanel p3 = new JPanel(new BorderLayout());
        p3.add(p1, BorderLayout.NORTH);
        p3.add(p2, BorderLayout.SOUTH);
        benchPanel.add(benchmarkButton, BorderLayout.WEST);
        benchPanel.add(p3, BorderLayout.CENTER);
        
        p.add(benchPanel, BorderLayout.SOUTH);
        
        JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, p, new JScrollPane(boardTable));
        content.add(split, BorderLayout.CENTER);
        return content;
    }
    
    
    private void runBenchmark(final long milliSecs, final int relation) throws Exception {
        final long pastNow = System.currentTimeMillis(); 
        Runnable boardWriter = new Runnable() {
            int id = 0;
            public void run() {
                while(System.currentTimeMillis() - pastNow < milliSecs) {
                    Board b = ModuleFactory.createBoard("board"+id++); 
                    try {
                        capi.write(cref, Arrays.asList(new Entry[]{b.asTuple()}));
                    } catch(Exception e) { 
                        logger.error("Error writing to Capi", e);
                        JOptionPane.showMessageDialog(f, e.getMessage(), "Error writing to Space", JOptionPane.ERROR_MESSAGE); 
                        //e.printStackTrace(); 
                    }
                }
            }
        };
        Runnable sensorWriter = new Runnable() {
            int id = 0;
            Feature[] allFeatures = Feature.values();
            public void run() {
                while(System.currentTimeMillis() - pastNow < milliSecs) {
                    EnumSet<Feature> features = EnumSet.noneOf(Feature.class);
                    Random r = new Random();
                    for(int i = 1; i < r.nextInt() % 3; i++) features.add(allFeatures[r.nextInt() % allFeatures.length]);
                    Sensor s = ModuleFactory.createSensor("sensor"+id++, features); 
                    try {
                        capi.write(cref, Arrays.asList(new Entry[]{s.asTuple()}));
                    } catch(Exception e) { 
                        logger.error("Error writing to Capi", e);
                        JOptionPane.showMessageDialog(f, e.getMessage(), "Error writing to Space", JOptionPane.ERROR_MESSAGE); 
                        //e.printStackTrace(); 
                    }

                    try {
                        Thread.currentThread().sleep(relation*1000);
                    } catch(Exception ex) { ex.printStackTrace(); }
                }
            }
        };
        Thread one = new Thread(boardWriter);
        Thread two = new Thread(sensorWriter);
        one.start();
        two.start();
    }
    
    public void showBoardDialog() {
        String id = JOptionPane.showInputDialog(f, "Board ID eingeben:");
        if(id == null || id.isEmpty()) return;
        Board b = null;
        b = ModuleFactory.createBoard(id); 
        try {
            capi.write(cref, Arrays.asList(new Entry[]{b.asTuple()}));
        } catch(Exception e) { 
            logger.error("Error writing to Capi", e);
            JOptionPane.showMessageDialog(f, e.getMessage(), "Error writing to Space", JOptionPane.ERROR_MESSAGE); 
            //e.printStackTrace(); 
        }
        
    }
    
    public void showSensorDialog() {
        //String id = JOptionPane.showInputDialog(f, "Board ID eingeben:");
        final JDialog diag = new JDialog(f, "Sensor erstellen", true);
        diag.setLayout(new GridLayout(0,1));
        JPanel idPanel = new JPanel(new BorderLayout());
        idPanel.add(new JLabel("ID:"), BorderLayout.WEST);
        final JTextField idField = new JTextField(15);
        idPanel.add(idField, BorderLayout.EAST);
        diag.add(idPanel);
        final java.util.List<JCheckBox> checkBoxes = new ArrayList<JCheckBox>();
        for(Feature f : Feature.values()) {
            JCheckBox check = new JCheckBox(f.getLabel());
            diag.add(check);
            checkBoxes.add(check);
        }
        JPanel buttons = new JPanel(new BorderLayout());
        JButton ok = new JButton("ok");
        ok.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                if(idField.getText().isEmpty()) {
                    JOptionPane.showMessageDialog(f, "You must provid an ID!");
                    return;
                }
                Component[] comps = diag.getComponents();
                EnumSet<Feature> featureSet = EnumSet.allOf(Feature.class);
                for(JCheckBox check : checkBoxes) {
                    if(!check.isSelected()) featureSet.remove(Feature.valueOf(check.getText().toUpperCase()));
                }
                if(featureSet.isEmpty() || featureSet.size() > 3) {
                    JOptionPane.showMessageDialog(f, "Sensors must contain at leat one and no more than three features!");
                    return;
                }
                Sensor sensor = null;
                sensor = ModuleFactory.createSensor(idField.getText(), featureSet);
                
                try {
                    capi.write(cref, Arrays.asList(new Entry[]{sensor.asTuple()}));
                } catch(Exception ex) { 
                    logger.error("Error writing to Capi", ex);
                    
                }
                diag.dispose();
            }
        });
        buttons.add(ok, BorderLayout.EAST);
        JButton cancel = new JButton("cancel");
        cancel.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                diag.dispose();
            }
        });
        buttons.add(cancel, BorderLayout.WEST);
        diag.add(buttons);
        diag.pack();
        diag.setVisible(true);
        
    }
    
    public static void main(String[] args) {
        Capi capi;
        if (args.length != 1) {
            System.out.println("URL needed!");
            System.out.println("Usage: java -cp <classpath> org.xvsm.example.Fifo http://localhost:8084/xvsm-0.8.3\n using embeded core");
            // use embeded xvsm core
            capi = CapiFactory.createCapi();
            //capi = new ClientCapi("http://localhost:8084/xvsm-0.8.3");
            //capi = new ClientCapi("http://localhost:8084/xvsm-0.8.3");
            //capi = new ClientCapi("http://localhost:8084/xvsm-0.8.3");
        } else {
        // Get an instance of the capi and initialize it.
        // Capi capi = CapiFactory.createCapi();
          capi = new ClientCapi(args[0]);
        }
        capi.init(true);
        try {
            ContainerRef cref = Util.getOrCreateNamedContainer(capi, sbc.TaskOne.CONTAINER_NAME, CoordinationTypes.FIFO);
            UI ui = new UI(capi, cref);
            logger.info("Container: " + cref);
        } catch(Exception ex) { 
            //ex.printStackTrace(); 
            logger.error("Error creating Container", ex);
        }
        
        CorsoBridge bridge = new CorsoBridge(capi);
    }
    
}
